/*
Hermes Core: General Purpose Mobile Agent Platform
Copyright (C) 2006 UNICAM - Università degli Studi di Camerino

Group leaders: Flavio Corradini and Emanuela Merelli

Developers: Ezio Bartocci, Diego Bonura, Rosario Culmone,
Davide Lorenzoli, Leonardo Mariani, Francesca Piersigilli, 
Lorenzo Scortichini, Leonardo Vito.

GNU Lesser Public License

This library is free software; you can redistribute it 
and/or modify it under the terms of the GNU Lesser General 
Public License as published by the Free Software Foundation, 
version 2.1 of the License.

This library is distributed in the hope that it will be useful, 
but WITHOUT ANY WARRANTY; without even the implied warranty of 
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
See the GNU Library General Public License for more details.

You should have received a copy of the GNU Library General Public 
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.

Emanuela Merelli
Dipartimento di Matematica ed Informatica
Università di Camerino
via Madonna delle Carceri, 62032 Camerino, Italy
E.Mail: emanuela.merelli@unicam.it
*/
package hermesV2.basicServices.monitoring;

import hermesV2.BasicServices;
import hermesV2.PlaceAddress;
import hermesV2.agent.Identificator;
import hermesV2.core.id.Identify;
import hermesV2.core.id.Trace;
import hermesV2.util.HermesLogger;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JToolBar;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

/**
 * DOCUMENT ME!
 * 
 * @author Diego Bonura
 * @author Ezio Bartocci
 * 
 * @version $Revision: 1.4 $
 */
class HermesGUI extends JFrame implements ActionListener {
    /**
	 * 
	 */
	private static final long serialVersionUID = -4975944156361732135L;

	/** DOCUMENT ME! */
    private JTabbedPane tabbedPane;

    /** DOCUMENT ME! */
    private JToolBar toolBar;

    /** DOCUMENT ME! */
    private JButton refreshViewButton;

    /** DOCUMENT ME! */
    private JButton launchAgentButton;

    /** DOCUMENT ME! */
    private DefaultMutableTreeNode topComponentsTree;

    /** DOCUMENT ME! */
    private DefaultMutableTreeNode topAgentsTree;

    /** DOCUMENT ME! */
    private DefaultMutableTreeNode topBornAgentsTree;

    /** DOCUMENT ME! */
    private DefaultTreeModel topAgentTreeModel;

    /** DOCUMENT ME! */
    private DefaultTreeModel topBornAgentsTreeModel;

    /** DOCUMENT ME! */
    private DefaultTreeModel topComponentsTreeModel;

    /** DOCUMENT ME! */
    private JTree componentsTree;

    /** DOCUMENT ME! */
    private JTree agentsTree;

    /** DOCUMENT ME! */
    private JTree bornAgentsTree;

    /** DOCUMENT ME! */
    private Identify identify;

    /** DOCUMENT ME! */
    private Trace trace;

    /** DOCUMENT ME! */
    private BasicServices basicServices;

    /**
     * Creates a new HermesGUI object.
     * 
     * @param currentPlaceAddress
     *            DOCUMENT ME!
     * @param basicServices
     *            DOCUMENT ME!
     * @param identify
     *            DOCUMENT ME!
     * @param trace
     *            DOCUMENT ME!
     * @param storePath
     *            DOCUMENT ME!
     */
    public HermesGUI(PlaceAddress currentPlaceAddress, BasicServices basicServices, Identify identify, Trace trace, String storePath) {
        this.identify = identify;
        this.trace = trace;
        this.basicServices = basicServices;
        //**Attribuisco un nome alla finestra ...
        setTitle("Hermes GUI");
        JFrame.setDefaultLookAndFeelDecorated(true);
        //**Rendo chiudibile la finestra ...
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        //**Stabilisco dimensioni e posizionamento ...
        setSize(new Dimension(450, 250));
        Container cp = getContentPane();
        //Creo la toolbar
        toolBar = new JToolBar();
        toolBar.setFloatable(false);
        launchAgentButton = new JButton();
        launchAgentButton.setToolTipText("Launch new user agent in the current place");
        launchAgentButton.setText("LaunchAgent");
        launchAgentButton.addActionListener(this);
        refreshViewButton = new JButton();
        refreshViewButton.setToolTipText("Refresh the current view");
        refreshViewButton.setText("Refresh");
        refreshViewButton.addActionListener(this);
        toolBar.add(launchAgentButton);
        toolBar.add(refreshViewButton);
        cp.add(toolBar, BorderLayout.PAGE_START);
        //Settaggio pannello place
        topComponentsTree = new DefaultMutableTreeNode("Place address: " + currentPlaceAddress);
        createHermesPlaceNodes(topComponentsTree, basicServices);
        topComponentsTreeModel = new DefaultTreeModel(topComponentsTree);
        componentsTree = new JTree(topComponentsTreeModel);
        topAgentsTree = new DefaultMutableTreeNode("Place address: " + currentPlaceAddress);
        createAgentsNodes(topAgentsTree, identify.getAllAgentsIdentificators());
        topAgentTreeModel = new DefaultTreeModel(topAgentsTree);
        agentsTree = new JTree(topAgentTreeModel);
        topBornAgentsTree = new DefaultMutableTreeNode("Place address: " + currentPlaceAddress);
        createBornAgentsNodes(topBornAgentsTree, trace.getAllBornsAgentsIdentificators());
        topBornAgentsTreeModel = new DefaultTreeModel(topBornAgentsTree);
        bornAgentsTree = new JTree(topBornAgentsTreeModel);
        tabbedPane = new JTabbedPane();
        tabbedPane.addTab("HermesPlace", null, new JScrollPane(componentsTree), "Information about the current place");
        tabbedPane.addTab("Agents", null, new JScrollPane(agentsTree), "Information about the current place");
        tabbedPane.addTab("bornAgents", null, new JScrollPane(bornAgentsTree), "Information about the agents trace table");
        cp.add(tabbedPane, BorderLayout.CENTER);
    }

    /**
     * DOCUMENT ME!
     * 
     * @param top
     *            DOCUMENT ME!
     * @param agentsIdentificators
     *            DOCUMENT ME!
     */
    private void createAgentsNodes(DefaultMutableTreeNode top, Identificator[] agentsIdentificators) {
        top.removeAllChildren();
        DefaultMutableTreeNode serviceAgentsTree = new DefaultMutableTreeNode("servicesAgents");
        top.add(serviceAgentsTree);
        DefaultMutableTreeNode userAgentsTree = new DefaultMutableTreeNode("userAgents");
        top.add(userAgentsTree);
        if (agentsIdentificators != null) {
            for (int i = 0; i < agentsIdentificators.length; i++) {
                Identificator agentId = agentsIdentificators[i];
                if (agentId != null) {
                    DefaultMutableTreeNode agent = new DefaultMutableTreeNode(agentId.getName());
                    agent.add(new DefaultMutableTreeNode("BornPlace:" + agentId.getBornPlaceAddress()));
                    agent.add(new DefaultMutableTreeNode("BornTime:" + agentId.getCreationDate()));
                    agent.add(new DefaultMutableTreeNode("SerialId:" + agentId.getSerialId()));
                    if (agentId.isServiceAgent()) {
                        DefaultMutableTreeNode keyWordsTree = new DefaultMutableTreeNode("DiscoveryKeyWords");
                        agent.add(keyWordsTree);
                        String[] tempDescription = basicServices.getDiscoveryServiceAgentInterface().getServiceDescription(agentId);
                        if (tempDescription != null) {
                            for (int j = 0; j < tempDescription.length; j++) {
                                keyWordsTree.add(new DefaultMutableTreeNode(tempDescription[j]));
                            }
                        } else {
                            keyWordsTree.add(new DefaultMutableTreeNode("Null"));
                        }
                        serviceAgentsTree.add(agent);
                    } else {
                        userAgentsTree.add(agent);
                    }
                }
            }
        }
        serviceAgentsTree.setUserObject((String) serviceAgentsTree.getUserObject() + "(" + serviceAgentsTree.getChildCount() + ")");
        userAgentsTree.setUserObject((String) userAgentsTree.getUserObject() + "(" + userAgentsTree.getChildCount() + ")");
    }

    /**
     * DOCUMENT ME!
     * 
     * @param top
     *            DOCUMENT ME!
     * @param basicServices
     *            DOCUMENT ME!
     */
    private void createHermesPlaceNodes(DefaultMutableTreeNode top, BasicServices basicServices) {
        top.removeAllChildren();
        DefaultMutableTreeNode memory = new DefaultMutableTreeNode("Memory");
        top.add(memory);
        DefaultMutableTreeNode memoryFree = new DefaultMutableTreeNode("FreeMemory");
        memoryFree.add(new DefaultMutableTreeNode(Runtime.getRuntime().freeMemory() + ""));
        memory.add(memoryFree);
        DefaultMutableTreeNode maxMemory = new DefaultMutableTreeNode("MaxMemory");
        maxMemory.add(new DefaultMutableTreeNode(Runtime.getRuntime().maxMemory() + ""));
        memory.add(maxMemory);
        DefaultMutableTreeNode totalMemory = new DefaultMutableTreeNode("TotalMemory");
        totalMemory.add(new DefaultMutableTreeNode(Runtime.getRuntime().totalMemory() + ""));
        memory.add(totalMemory);
        DefaultMutableTreeNode threadCount = new DefaultMutableTreeNode("Numbers of threads");
        top.add(threadCount);
        threadCount.add(new DefaultMutableTreeNode(getThreadsCount() + ""));
        DefaultMutableTreeNode components = new DefaultMutableTreeNode("Components");
        top.add(components);
        DefaultMutableTreeNode componentsOn = new DefaultMutableTreeNode("Components On");
        components.add(componentsOn);
        DefaultMutableTreeNode componentsOff = new DefaultMutableTreeNode("Components Off");
        components.add(componentsOff);
        if (basicServices.getDiscoveryServiceAgentInterface() == null) {
            componentsOff.add(new DefaultMutableTreeNode("Discovery component"));
        } else {
            componentsOn.add(new DefaultMutableTreeNode("Discovery component"));
        }
        if (basicServices.getGenesisInterface() == null) {
            componentsOff.add(new DefaultMutableTreeNode("Genesis component"));
        } else {
            componentsOn.add(new DefaultMutableTreeNode("Genesis component"));
        }
        if (basicServices.getMoveInterface() == null) {
            componentsOff.add(new DefaultMutableTreeNode("Mobility component"));
        } else {
            componentsOn.add(new DefaultMutableTreeNode("Mobility component"));
        }
        if (basicServices.getReceiveInterface() == null) {
            componentsOff.add(new DefaultMutableTreeNode("Communication component"));
        } else {
            componentsOn.add(new DefaultMutableTreeNode("Communication component"));
        }
        if (componentsOff.isLeaf() == true) {
            componentsOff.add(new DefaultMutableTreeNode("Null"));
        }
        if (componentsOn.isLeaf() == true) {
            componentsOff.add(new DefaultMutableTreeNode("Null"));
        }
    }

    /**
     * DOCUMENT ME!
     * 
     * @return DOCUMENT ME!
     */
    private int getThreadsCount() {
        ThreadGroup group = Thread.currentThread().getThreadGroup();
        ThreadGroup rootGroup = null;
        while (group != null) {
            rootGroup = group;
            group = group.getParent();
        }
        return rootGroup.activeCount();
    }

    /**
     * DOCUMENT ME!
     * 
     * @param top
     *            DOCUMENT ME!
     * @param bornsAgentsIdentificators
     *            DOCUMENT ME!
     */
    private void createBornAgentsNodes(DefaultMutableTreeNode top, String[] bornsAgentsIdentificators) {
        top.removeAllChildren();
        DefaultMutableTreeNode agents = new DefaultMutableTreeNode("Agents");
        DefaultMutableTreeNode agent;
        if (bornsAgentsIdentificators != null) {
            for (int i = 0; i < bornsAgentsIdentificators.length; i++) {
                String agentId = bornsAgentsIdentificators[i];
                if (agentId != null) {
                    agent = new DefaultMutableTreeNode(agentId);
                    agent.add(new DefaultMutableTreeNode("CurrentPlaceAddress:" + trace.getCurrentAddress(agentId)));
                } else {
                    agent = new DefaultMutableTreeNode("Null");
                }
                agents.add(agent);
            }
        }
        agents.setUserObject((String) agents.getUserObject() + "(" + agents.getChildCount() + ")");
        top.add(agents);
    }

    /**
     * DOCUMENT ME!
     * 
     * @param e
     *            DOCUMENT ME!
     */
    public void actionPerformed(ActionEvent e) {
        Object source = e.getSource();
        try {
            if (source == refreshViewButton) {
                createHermesPlaceNodes(topComponentsTree, basicServices);
                createAgentsNodes(topAgentsTree, identify.getAllAgentsIdentificators());
                createBornAgentsNodes(topBornAgentsTree, trace.getAllBornsAgentsIdentificators());
                topComponentsTreeModel.nodeStructureChanged(topComponentsTree);
                topAgentTreeModel.nodeStructureChanged(topAgentsTree);
                topBornAgentsTreeModel.nodeStructureChanged(topBornAgentsTree);
            }
            if (source == launchAgentButton) {
                final JFileChooser fc = new JFileChooser();
                fc.addChoosableFileFilter(new MyFileFilter("class", "Agent class file"));
                fc.setAcceptAllFileFilterUsed(false);
                int returnVal = fc.showOpenDialog(tabbedPane);
                if (returnVal == JFileChooser.APPROVE_OPTION) {
                    File file = fc.getSelectedFile();
                    String className = file.getName().substring(0, file.getName().indexOf(".class"));
                    try {

                        File directory = new File(file.getParent());
                        //                      Just to know the package name!
                        FileInputStream fIn = new FileInputStream(directory.toString() + System.getProperty("file.separator") + className + ".class");
                        String packageName = ClassParser.getPackageName(fIn);

                        fIn.close();
                        Vector<URL> vectorDir = new Vector<URL>();
                        vectorDir.add(directory.toURI().toURL());
                        //Creo una url che preceda il package name
                        String tempDir = directory.toURI().toURL().toString();
                        File tempDirectory = directory;
                        StringTokenizer st = new StringTokenizer(tempDir, ".");
                        tempDirectory = tempDirectory.getParentFile();
                        if (tempDirectory != null) {
                            vectorDir.add(tempDirectory.toURI().toURL());
                            while (st.hasMoreTokens()) {
                                st.nextToken();
                                if (tempDirectory != null) {
                                    tempDirectory = tempDirectory.getParentFile();
                                    vectorDir.add(tempDirectory.toURI().toURL());
                                }
                            }
                        }
                        URL[] urls = vectorDir.toArray(new URL[vectorDir.size()]);
                        URLClassLoader loader = new URLClassLoader(urls);
                        
                        Class<?> c = Class.forName(packageName + "." + className, true, loader);
                        basicServices.getGenesisInterface().createAgent(c, c.getName());
                    } catch (ClassNotFoundException cce) {
                        HermesLogger.log(HermesLogger.WARNING, "ClassNotFoundException", cce);
                    } catch (MalformedURLException mue) {
                        HermesLogger.log(HermesLogger.WARNING, "MalformedURLException", mue);
                    } catch (IOException ioe) {
                        HermesLogger.log(HermesLogger.WARNING, "Something wrong with the class file", ioe);
                    }
                }
            }
        } catch (NullPointerException evt) {
        }
    }
}